package top.fyxxxx.downloader.utils;

import android.os.Message;

import java.io.BufferedInputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

public class DownloadTask implements Runnable{
    private File save,config;
    public String url;
    private long start=0;
    private long cur=0;
    private DownloadListener listener;
    private List<DownloadListener> listeners;
    private DownloadManager.MyHandler handler;
    ThreadPoolExecutor executor;
    public DownloadTask(String url, final String savepath, ThreadPoolExecutor executor, DownloadManager.MyHandler myHandler) {
        save=new File(savepath);
        this.executor=executor;
        this.url=url;
        config=new File(savepath+".download");
        if(!save.getParentFile().exists())save.getParentFile().mkdirs();
        listeners=new ArrayList<>();
        handler=myHandler;
        this.listener=new DownloadListener() {

            @Override
            public void start() {
                if(listeners.isEmpty())System.out.println("Empty");
                else System.out.println("Not Empty");
                for(final DownloadListener l:listeners){
                    handler.obtainMessage(0, new DownloadManager.DownloadCallback() {
                        @Override
                        public void execute() {
                            System.out.println("start listener");
                            l.start();
                        }
                    }).sendToTarget();
                }
            }

            @Override
            public void loading(final long cur, final long total) {
                saveProgress();
                for(final DownloadListener l:listeners){
                    handler.obtainMessage(0, new DownloadManager.DownloadCallback() {
                        @Override
                        public void execute() {
                            l.loading(cur, total);
                        }
                    }).sendToTarget();
                }
            }

            @Override
            public void complete(final String path) {
                boolean f=config.delete();
                for(final DownloadListener l:listeners){
                    handler.obtainMessage(0, new DownloadManager.DownloadCallback() {
                        @Override
                        public void execute() {
                            l.complete(path);
                        }
                    }).sendToTarget();
                }
            }

            @Override
            public void fail(final int code, final String message) {
                for(final DownloadListener l:listeners){
                    handler.obtainMessage(0, new DownloadManager.DownloadCallback() {
                        @Override
                        public void execute() {
                            l.fail(code,message);
                        }
                    }).sendToTarget();
                }
            }

            @Override
            public void pause() {
                saveProgress();
                for(final DownloadListener l:listeners){
                    handler.obtainMessage(0, new DownloadManager.DownloadCallback() {
                        @Override
                        public void execute() {
                            l.pause();
                        }
                    }).sendToTarget();
                }
            }

            @Override
            public void loadfail(final String message) {
                saveProgress();
                for(final DownloadListener l:listeners){
                    handler.obtainMessage(0, new DownloadManager.DownloadCallback() {
                        @Override
                        public void execute() {
                            l.loadfail(message);
                        }
                    }).sendToTarget();
                }
            }
        };
    }
    private void saveProgress(){
        try {
            DataOutputStream out=new DataOutputStream(new FileOutputStream(config));
            out.writeLong(cur);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void addListener(DownloadListener listener){
        listeners.add(listener);
    }
    public void start(){
        System.out.println("task start");
        executor.execute(this);
    }
    private Thread curThread;
    public void pause(){
        if(curThread!=null)
            curThread.interrupt();
    }

    public String filename(){
        return save.getName();
    }
    @Override
    public void run() {
        if(config.exists()){
            try {
                DataInputStream in=new DataInputStream(new FileInputStream(config));
                start = in.readLong();
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        cur=start;
        listener.start();
        try {
            curThread=Thread.currentThread();
            Response response=DownloadManager.download(url,start);
            if(response.code()>=400){
                listener.fail(response.code(),null);
                return;
            }
            long length = response.body().contentLength();
            if (length == 0||length == -1) {
                // 说明文件已经下载完
                listener.loading(cur, start+length);
                listener.complete(String.valueOf(save.getAbsoluteFile()));
                return;
            }
            // 保存文件到本地
            InputStream is = null;
            RandomAccessFile randomAccessFile = null;
            BufferedInputStream bis = null;
            byte[] buff = new byte[2048];
            int len = 0;
            try {
                is = response.body().byteStream();
                bis = new BufferedInputStream(is);
                // 随机访问文件，可以指定断点续传的起始位置
                randomAccessFile = new RandomAccessFile(save, "rwd");
                if(!save.exists())
                    randomAccessFile.setLength(length);
                randomAccessFile.seek(start);
                long curtime=System.currentTimeMillis();
                listener.loading(cur, start+length);
                while (!curThread.isInterrupted()&&(len = bis.read(buff)) != -1) {
                    randomAccessFile.write(buff, 0, len);
                    cur+=len;
                    if(System.currentTimeMillis()-curtime>=300){
                        listener.loading(cur, start+length);
                        curtime=System.currentTimeMillis();
                    }
                }
                listener.loading(cur, start+length);
                if(curThread.isInterrupted())throw new InterruptedException();
                // 下载完成
                listener.complete(String.valueOf(save.getAbsoluteFile()));
            } catch (IOException e) {
                e.printStackTrace();
                listener.loadfail(e.getMessage());
            } catch (InterruptedException e) {
                listener.pause();
            } finally {
                try {
                    if (is != null) {
                        is.close();
                    }
                    if (bis != null) {
                        bis.close();
                    }
                    if (randomAccessFile != null) {
                        randomAccessFile.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            listener.fail(-1,e.getMessage());
        }
    }
}
